package design.pattern.Lu09CommandPattern;

import java.util.ArrayList;
import java.util.List;

/**
 * @program JavaBase
 * @description: 命令模式 todo|undo
 * @author: zhanglu
 * @create: 2020-04-05 10:26:00
 */
public class Lu09CommandPattern03 {

    public static void main(String[] args) {
        OperationApi operation = new Operation();

        AddCommand03 addCmd = new AddCommand03(operation, 12);
        SubCommand03 subCmd = new SubCommand03(operation, 2);

        //2：把命令设置到持有者，就是计算器里面
        Calculator calculator = new Calculator();
        calculator.setAddCmd(addCmd);
        calculator.setSubCmd(subCmd);

        //3:模拟按下按钮，测试一下
        calculator.addPressed();
        System.out.println("一次加法运算后的结果为：" +operation.get());
        calculator.subPressed();
        System.out.println("一次减法运算后的结果为：" +operation.get());

        //测试撤消
        calculator.undoPressed();
        System.out.println("撤销一次后的结果为：" +operation.get());
        calculator.undoPressed();
        System.out.println("再撤销一次后的结果为：" +operation.get());

        //测试恢复
        calculator.redoPressed();
        System.out.println("恢复操作一次后的结果为：" +operation.get());
        calculator.redoPressed();
        System.out.println("再恢复操作一次后的结果为：" +operation.get());

    }

}

interface OperationApi{

    int get();

    void add(int num);

    void sub(int num);

}

interface Command03{

    void execute();

    void undo();

}

class Operation implements OperationApi{

    private int result;

    @Override
    public int get() {
        return this.result;
    }

    @Override
    public void add(int num) {
        this.result += num;
    }

    @Override
    public void sub(int num) {
        this.result -= num;
    }
}

class AddCommand03 implements Command03{

    private OperationApi operationApi;
    private int num;

    public AddCommand03(OperationApi operationApi, int num){
        this.operationApi = operationApi;
        this.num = num;
    }

    @Override
    public void execute() {
        this.operationApi.add(this.num);
    }

    @Override
    public void undo() {
        this.operationApi.sub(this.num);
    }

}

class SubCommand03 implements Command03{

    private OperationApi operationApi;
    private int num;

    public SubCommand03(OperationApi operationApi, int num){
        this.operationApi = operationApi;
        this.num = num;
    }

    @Override
    public void execute() {
        this.operationApi.sub(this.num);
    }

    @Override
    public void undo() {
        this.operationApi.add(this.num);
    }
}

class Calculator{

    //命令操作的历史记录，在撤销的时候用
    private List<Command03> undoCmds = new ArrayList<>();

    //命令被撤销的历史记录，在回复的时候用
    private List<Command03> redoCmds = new ArrayList<>();

    private Command03 addCmd;
    private Command03 subCmd;

    public void setAddCmd(Command03 addCmd){
        this.addCmd = addCmd;
    }

    public void setSubCmd(Command03 subCmd){
        this.subCmd = subCmd;
    }

    public void addPressed(){
        this.addCmd.execute();
        this.undoCmds.add(this.addCmd);
    }

    public void subPressed(){
        this.subCmd.execute();
        this.undoCmds.add(this.subCmd);
    }

    public void undoPressed(){
        if(this.undoCmds.size() > 0){
            //取出一个最近执行的命令，来撤销
            Command03 cmd = this.undoCmds.get(this.undoCmds.size() - 1);
            cmd.undo();
            //若有恢复功能，则把该命令记录
            this.redoCmds.add(cmd);
            //undo操作完毕，也记录到恢复里，则可以把undo执行的命令删了
            this.undoCmds.remove(cmd);
        }else {
            System.out.println("很抱歉，没有可撤销的命令");
        }
    }

    public void redoPressed(){
        if(this.redoCmds.size() > 0){
            Command03 cmd = this.redoCmds.get(this.redoCmds.size() - 1);
            cmd.execute();
            this.undoCmds.add(cmd);
            this.redoCmds.remove(cmd);
        }else {
            System.out.println("很抱歉，没有可恢复的命令");
        }
    }

}